﻿#define _CRT_SECURE_NO_WARNINGS 1

//一个数组中只有两个数字是出现一次，其他所有数字都出现了两次。
//编写一个函数找出这两个只出现一次的数字。
//
//例如：
//
//有数组的元素是：1，2，3，4，5，1，2，3，4，6
//只有5和6只出现1次，要找出5和6.

//找出一个只出现过一次的数字的问题处理方法就是找一个数字把里面所有的数字都异或一遍，
//利用异或两次等于没异或的特点来处理。那么如果有两个数字都只出现了一次，
//那么如此得到的应该是两个数异或的结果。首先这个结果肯定不是0（要不然就全都配对了），
//所以里面一定至少一位是一。找出值为1的一位，以这一位的值将结果分为两组。
//例如1 2 3 4 1 2，异或完的结果应该是3 ^ 4得到的111，那么随便找一位就行了。
//例如找最低位，那么这一位是1的有1 3 1，是0的有2 4 2，由于是利用异或结果为1的某一位分的组，
//所以两个待查询数字一定分别在两组中。所以再找两个变量，分别异或两组数，即可找到这两个数。
//void findTwoNum(int arr[], int n, int* pnum1, int* pnum2)
//{
//	int i;
//	int sum = 0;
//	​
//		for (i = 0; i < 9; i++)
//		{
//			sum ^= arr[i];
//		} //先找到两个数互相异或的结果
//	​
//		int pos;
//	for (i = 0; i < 32; i++)
//	{
//		if (sum & 1 << i)
//		{
//			pos = i;
//			break;
//		}
//	} //再找到有分歧的一位。在这一位上，两个数一定是一个1一个0
//	​
//		* pnum1 = *pnum2 = 0;
//	for (i = 0; i < 10; i++)
//	{
//		if (arr[i] & 1 << pos)
//		{
//			*pnum1 ^= arr[i]; //这一位是1的，放在数1里
//		}
//		else
//		{
//			*pnum2 ^= arr[i]; //这一位是0的，放在数2里
//		}
//	}
//}


//#include<stdio.h>
//#include<string.h>
//#include<stdlib.h>
//
//int main()
//{
//	int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int* ptr = malloc((sz+1) * sizeof(int));
//	if (ptr == NULL)
//	{
//		perror("malloc");
//		return;
//	}
//	memset(ptr, 0, (sz+1) * sizeof(int));
//	for (int i = 0; i < sz; i++)
//	{
//		ptr[arr[i]]++;
//	}
//	for (int i = 0; i < sz; i++)
//	{
//		if (ptr[i] == 1)
//		{
//			printf("%d ", i);
//		}
//	}
//	printf("\n");
//	return 0;
//}



////模拟实现strncpy
//#include<stdio.h>
//
////char* strncpy(char* dest, const char* src, size_t n)
////dest -- 指向用于存储复制内容的目标数组。
////src -- 要复制的字符串。
////n -- 要从源中复制的字符数。
//char* my_strncpy(char* dest, const char* src, size_t n) 
//{
//	char* ret = dest; //保存目标数组的首地址
//	while (n--)
//	{
//		*dest++ = *src++;
//	}
//	*dest = '\0'; //在尾部加上'\0'
//	return ret; 
//}
//
//int main()
//{
//	char dest[20] = { 0 };
//	char src[] = "abcdef";
//	printf(my_strncpy(dest, src, 3));
//	printf("\n");
//	return 0;
//}

char* __cdecl strncpy(
	char* dest,
	const char* source,
	size_t count
)
{
	char* start = dest;

	while (count && (*dest++ = *source++) != '\0')    /* copy string */
		count--;

	if (count)                              /* pad out with zeroes */
		while (--count)
			*dest++ = '\0';

	return(start);
}





////模拟实现strncat
//#include<stdio.h>
//
//char* my_strncat(char* dest, const char* src, size_t n)
//{
//	char* ret = dest;
//	int num = 1;
//	while (*dest)//找dest的尾
//	{
//		dest++; 
//	}
//	while (num <= n)
//	{
//		*dest++ = *src++; 
//		num++;
//	}
//	*dest = '\0'; //在尾部加上'\0'
//	return ret; 
//}
//
//int main()
//{
//	char dest[20] = "abcdef";
//	char src[] = "abc";
//	printf(my_strncat(dest, src, 2));
//	printf("\n");
//	return 0;
//}

char* __cdecl strncat(
	char* front,
	const char* back,
	size_t count
)
{
	char* start = front;

	while (*front++)
		;
	front--;

	while (count--)
		if ((*front++ = *back++) == 0)
			return(start);

	*front = '\0';
	return(start);
}

//C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数（类型为 int 型）。
//该函数返回转换后的长整数，如果没有执行有效的转换，则返回零。
//模拟实现atoi函数
//※atoi的规则是：跳过不可见字符，碰到负号或者数字开始转换，转换到非数字字符为止。
#include<stdio.h>
#include<assert.h>
#include<ctype.h>
#include<stdlib.h>
enum State
{
	VAILD, //合法
	INVAILD //非法
}Sta = INVAILD;//创造变量默认为非法

int my_atoi(const char* str)
{
	assert(str);
	if (*str == '\0')
	{
		return 0;
	}
	while (isspace(*str))//跳过空格
	{
		str++; 
	}
	int flag = 1;
	if (*str == '+')
	{
		flag = 1; //正数
		str++;
	}
	else if (*str == '-')
	{
		flag = -1; //负数
		str++;
	}
	long long ret = 0;
	while (*str != '\0')//转换为整型
	{
		if (isdigit(*str))
		{
			ret = ret * 10 + flag * (*str - '0');//减去字符0，才是数字0
			if (ret > INT_MAX || ret < INT_MIN)
			{
				return 0;
			}
		}
		else
		{
			return (int)ret;//强制类型转化为int（函数的返回值是int）
		}
		str++;
	}
	if (*str == '\0')
	{
		Sta = VAILD; //正常转换完了，到末尾的 \0
	}
	return (int)ret;
}

int main()
{
	char arr[20] = "-1234";
	int ret = my_atoi(arr);
	if (Sta == VAILD)
	{
		printf("合法转换:%d\n", ret);
	}
	else if (Sta == INVAILD)
	{
		printf("非法转换:%d\n", ret);
	}
	return 0;
}
